%%% ====================================================================
%%% Writes record definitions, to be used with Erlsom.
%%% 
%%% Copyright (C) 2006 Willem de Jong
%%%
%%% This program is free software; you can redistribute it and/or modify
%%% it under the terms of the GNU General Public License as published by 
%%% the Free Software Foundation; either version 2 of the License, or 
%%% (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful, but
%%% WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License 
%%% along with this program; if not, write to the Free Software 
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
%%% USA
%%%
%%% Author contact: w.a.de.jong@gmail.com
%%% ====================================================================

%%% Version: 0.0.1

%%% Writes record defintions, taking a 'model' (from erlsom_compile) as
%%% input.

-module(erlsom_writeHrl).
-export([writeHrl/3]).
%% internal exports
-export([writeType/2]).
-export([writeAttribute/2]).

-include("erlsom_parse.hrl").
-include("erlsom.hrl").

%% debug(Text) -> io:format("~p~n", [Text]).

%% debug(Text1, Text2) ->
  %% io:format("~p ~p~n", [Text1, Text2]).

writeHrl(Xsd, Prefix, Namespaces) ->

%% compile file
  Result = erlsom:compile(Xsd, Prefix, Namespaces),
  case Result of
    {ok, #model{tps = Types}} -> 
      Acc = header(),
      writeTypes(Types, Acc);
    {error, Error} -> 
      io:format("Error while compiling file: ~p~n", [Error])
  end.

header() ->
"%% HRL file generated by ERLSOM\n"
"%%\n"
"%% It is possible to change the name of the record fields.\n"
"%%\n"
"%% It is possible to add default values, but be aware that these will\n"
"%% only be used when *writing* an xml document.\n\n".

writeTypes(Types, Acc) ->
  Acc ++ lists:foldl({erlsom_writeHrl, writeType}, [], Types).

writeType(#type{nm = '_document'}, Acc) ->
  Acc;
%% writeType(Type, []) -> writeType2(Type);
writeType(Type, Acc) ->
  Acc ++ writeType2(Type).

writeType2(#type{nm = Name, els = Elements, atts = Attributes}) ->
  "-record('" ++ atom_to_list(Name)
  ++ joinStrings("', {anyAttribs",
                 joinStrings(writeAttributes(Attributes), 
		             writeElements(Elements)))
  ++ "}).\n".

writeElements(Elements) ->
  writeElements(Elements, []).
writeElements([], Acc) ->
  Acc;
writeElements([Element], Acc) ->
  Acc ++ writeElement(Element);
writeElements([Element | Tail], Acc) ->
  writeElements(Tail, Acc  ++ writeElement(Element) ++ ", ").

writeElement(#el{alts = Alternatives}) ->
  writeAlternatives(Alternatives).

%% easy case: 1 alternative (not a choice), 'real' element (not a group)
writeAlternatives([]) ->
  "any_strict_but_none_defined";
writeAlternatives([#alt{tag = '#any'}]) ->
  "any";
writeAlternatives([#alt{tag = Tag, rl = true}]) ->
  "'" ++ erlsom_lib:nameWithoutPrefix(atom_to_list(Tag)) ++ "'";
writeAlternatives([#alt{tag = Tag, rl = false, tp = {_,_}}]) ->
  "'" ++ erlsom_lib:nameWithoutPrefix(atom_to_list(Tag)) ++ "'";
writeAlternatives([#alt{rl = false, tp=Tp}]) ->
  "'" ++ erlsom_lib:nameWithoutPrefix(atom_to_list(Tp)) ++ "'";
%% more than 1 alternative: a choice
writeAlternatives([#alt{} | _Tail]) ->
  "choice".

writeAttributes(Attributes) ->
  lists:foldl({erlsom_writeHrl, writeAttribute}, [], Attributes).

writeAttribute(#att{nm = Name}, []) -> "'" ++ atom_to_list(Name) ++ "'";
writeAttribute(#att{nm = Name}, Acc) -> Acc  ++ ", '" ++ atom_to_list(Name) ++ "'".

joinStrings([], StringB) ->
  StringB;
joinStrings(StringA, []) ->
  StringA;
joinStrings(StringA, StringB) ->
  StringA ++ ", " ++ StringB.
